package org.study.local.boot.util;

import com.alibaba.fastjson2.JSON;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 文件工具类
 * <p>
 * bit：位或比特。bit 的缩写是 b，它是计算机中的最小数据单位(属于二进制的范畴，其实就是0或者1)
 * Byte：字节。Byte 的缩写是 B，它是计算机文件大小的基本计算单位(如一个字符是1Byte，一个汉字是2Byte)。一个 Byte 由 8 bits 组成。
 * 换算关系：1Byte=8bit、1KB=1024B、1MB=1024KB、1GB=1024MB、1TB=1024GB
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2024年05月18日
 */
@Slf4j
public class FileUploadUtils {
    private static final String DOT_EN = ".";

    @Getter
    public enum SizeUnit {
        B("B", "字节，", 0),
        KB("KB", "千字节(1KB=1024B)", 10),
        MB("MB", "兆字节(1MB＝1024KB)", 20),
        GB("GB", "吉字节(1GB＝1024MB)", 30),
        TB("TB", "太字节(1TB=1024GB)", 40);

        SizeUnit(String unit, String desc, int digits) {
            this.unit = unit;
            this.desc = desc;
            this.digits = digits;
        }

        /**
         * 单位名称
         */
        private String unit;
        /**
         * 单位描述
         */
        private String desc;
        /**
         * 使用位运算转换成字节时，需要左移的位数
         */
        private int digits;
    }

    /**
     * 获取文件扩展名
     *
     * @param multipartFile 多媒体文件
     * @return java.lang.String
     */
    public static String getFileExtension(MultipartFile multipartFile) {
        log.info("当前待上传的文件：{}", multipartFile);
        if (multipartFile != null) {
            String name = multipartFile.getName();
            int lastIndexOf = name.lastIndexOf(DOT_EN);
            if (lastIndexOf > 0) {
                return name.substring(lastIndexOf + 1);
            }
        }
        throw new RuntimeException("文件没有扩展名");
    }

    /**
     * 校验文件格式是否为指定格式
     *
     * @param multipartFile 多媒体文件
     * @param allowTypes    允许的文件类型列表
     * @return boolean
     */
    public static boolean isFileTypeAllowed(MultipartFile multipartFile, List<String> allowTypes) {
        boolean isFileTypeAllowed = false;
        if (CollectionUtils.isNotEmpty(allowTypes)) {
            String filename = multipartFile.getOriginalFilename();
            List<String> lowerCaseList = allowTypes.stream().map(item -> item.toLowerCase()).collect(Collectors.toList());
            if (StringUtils.isNotBlank(filename) && filename.lastIndexOf(DOT_EN) > 0) {
                String substring = filename.substring(filename.lastIndexOf(DOT_EN) + 1);
                if (StringUtils.isNotBlank(substring)) {
                    isFileTypeAllowed = lowerCaseList.contains(substring.toLowerCase());
                }
            }
        }
        log.info("是否允许：{}，当前文件名称：{}，系统允许的文件类型：{}", isFileTypeAllowed, multipartFile.getOriginalFilename(), JSON.toJSONString(allowTypes));
        return isFileTypeAllowed;
    }

    /**
     * 判断文件是否超过指定大小
     *
     * @param multipartFile 多媒体文件
     * @param expectedSize  期望的文件大小上限
     * @param sizeUnit      期望的文件大小单位
     * @return boolean
     */
    public static boolean isFileSizeOver(MultipartFile multipartFile, long expectedSize, SizeUnit sizeUnit) {
        long fileSize = multipartFile.getSize();
        // 根据指定的大小、单位换算成字节
        long expectedBytes = expectedSize << sizeUnit.getDigits();
        boolean isFileSizeOver = fileSize >= expectedBytes;
        log.info("是否超限：{}，当前文件大小：{}，系统配置的文件大小阈值：{}", isFileSizeOver, fileSize, expectedBytes);
        return isFileSizeOver;
    }
}
